#include "napi/native_api.h"
// 导入NDK接口头文件
#include "hilog/log.h"
#include "ohcamera/camera.h"
#include "ohcamera/camera_input.h"
#include "ohcamera/capture_session.h"
#include "ohcamera/photo_output.h"
#include "ohcamera/preview_output.h"
#include "ohcamera/video_output.h"
#include "ohcamera/camera_manager.h"
#include <arm-linux-ohos/bits/alltypes.h>
#include <multimedia/image_framework/image_receiver_mdk.h>



#undef LOG_TAG
#define LOG_TAG "hmz"

#undef LOG_DOMAIN
#define LOG_DOMAIN 0x1100

void PreviewOutputOnError(Camera_PreviewOutput *previewOutput, Camera_ErrorCode errorCode) {
    OH_LOG_INFO(LOG_APP, "PreviewOutput errorCode = %{public}d", errorCode);
}

void PreviewOutputOnFrameEnd(Camera_PreviewOutput *previewOutput, int32_t frameCount) {
    OH_LOG_INFO(LOG_APP, "PreviewOutput frameCount = %{public}d", frameCount);
}

void PreviewOutputOnFrameStart(Camera_PreviewOutput *previewOutput) {
    OH_LOG_INFO(LOG_APP, "PreviewOutputOnFrameStart");
}
PreviewOutput_Callbacks *GetPreviewOutputListener(void) {
    static PreviewOutput_Callbacks previewOutputListener = {.onFrameStart = PreviewOutputOnFrameStart,
                                                            .onFrameEnd = PreviewOutputOnFrameEnd,
                                                            .onError = PreviewOutputOnError};
    return &previewOutputListener;
}

bool InitCamera(char *surfaceId , char * xSurfaceId) {

    OH_LOG_ERROR(LOG_APP, "surfaceID %{public}s xsurfaceID %{public}s", surfaceId, xSurfaceId);

    Camera_Manager *cameraManager = nullptr;
    Camera_Device *cameras = nullptr;
    Camera_OutputCapability *cameraOutputCapability = nullptr;

    uint32_t size = 0;
    uint32_t cameraDeviceIndex = 0;
    char *previewSurfaceId = surfaceId;
    Camera_ErrorCode ret = OH_Camera_GetCameraManager(&cameraManager);
    if (cameraManager == nullptr || ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_Camera_GetCameraManager failed.");
        return false;
    }
    
    ret = OH_CameraManager_GetSupportedCameras(cameraManager, &cameras, &size);
    if (cameras == nullptr || size < 0 || ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameras failed.");
        return false;
    }
    
    for (int index = 0; index < size; index++) {
        OH_LOG_ERROR(LOG_APP, "cameraId  =  %{public}s ", cameras[index].cameraId);             // 获取相机ID
        OH_LOG_ERROR(LOG_APP, "cameraPosition  =  %{public}d ", cameras[index].cameraPosition); // 获取相机位置
        OH_LOG_ERROR(LOG_APP, "cameraType  =  %{public}d ", cameras[index].cameraType);         // 获取相机类型
        OH_LOG_ERROR(LOG_APP, "connectionType  =  %{public}d ", cameras[index].connectionType); // 获取相机连接类型
    }
    
    
    // 获取相机设备支持的输出流能力
    ret = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager, &cameras[cameraDeviceIndex],
                                                              &cameraOutputCapability);
    if (cameraOutputCapability == nullptr || ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameraOutputCapability failed.");
        return false;
    }

    if (cameraOutputCapability->previewProfilesSize < 0) {
        OH_LOG_ERROR(LOG_APP, "previewProfilesSize == null");
        return false;
    }
    Camera_Profile *previewProfile = cameraOutputCapability->previewProfiles[0];
    
//     // 创建相机预览流
    Camera_PreviewOutput *previewOutput = nullptr;
    ret = OH_CameraManager_CreatePreviewOutput(cameraManager, previewProfile, previewSurfaceId, &previewOutput);
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput failed. %{public}d", ret);
        return false;
    }

//     Camera_PreviewOutput *xPreviewOutput = nullptr;
//     ret = OH_CameraManager_CreatePreviewOutput(cameraManager, previewProfile, xSurfaceId, &xPreviewOutput);
//     if (ret != CAMERA_OK) {
//         OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput failed. %{public}d", ret);
//         return false;
//     }


    ret = OH_PreviewOutput_RegisterCallback(previewOutput, GetPreviewOutputListener());
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_RegisterCallback failed.");
    }

    //创建一个会话
    Camera_CaptureSession *captureSession = nullptr;
    ret = OH_CameraManager_CreateCaptureSession(cameraManager, &captureSession);
    if (captureSession == nullptr || ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed.");
        return false;
    }
    
    //配置会话
    ret = OH_CaptureSession_BeginConfig(captureSession);
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed.");
        return false;
    }

    // 创建相机输入流
    Camera_Input *cameraInput = nullptr;
    ret = OH_CameraManager_CreateCameraInput(cameraManager, &cameras[0], &cameraInput);
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCameraInput failed. %{public}d", ret);
        return false;
    }

    // 打开相机
    ret = OH_CameraInput_Open(cameraInput);
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Open failed.");
        return false;
    }
    
    // 会话使能，加入相机输入输出流
    //  向会话中添加相机输入流
    ret = OH_CaptureSession_AddInput(captureSession, cameraInput);
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddInput failed.");
        return false;
    }

    // 向会话中添加预览输出流
    ret = OH_CaptureSession_AddPreviewOutput(captureSession, previewOutput);
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPreviewOutput failed.");
        return false;
    }

//     // 向会话中添加预览输出流
//     ret = OH_CaptureSession_AddPreviewOutput(captureSession, xPreviewOutput);
//     if (ret != CAMERA_OK) {
//         OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPreviewOutput failed.");
//         return false;
//     }

    // 提交会话配置
    ret = OH_CaptureSession_CommitConfig(captureSession);
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed.");
        return false;
    }

    // 启动会话
    ret = OH_CaptureSession_Start(captureSession);
    if (ret != CAMERA_OK) {
        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed.");
        return false;
    }
    
    return true;
}

ImageReceiverNative *imageReceiverNative = nullptr;
napi_env cur_env = nullptr;

napi_value InitImageReceiverNative(napi_env env, napi_callback_info info) {
    int32_t ret;
    napi_value result = nullptr;
    napi_value imageReceiver;
    size_t number = 2;
    napi_value args[2];

    napi_get_cb_info(env, info, &number, args, nullptr, nullptr);
    
    //XComponent 的 surfaceID
    char xSurfaceId[128] = {0};
    size_t len;
    napi_get_value_string_utf8(env, args[0], xSurfaceId, sizeof(xSurfaceId), &len);
    
//     struct OhosImageReceiverInfo ohosImageReceiverInfo = {640, 480, OHOS_IMAGE_FORMAT_JPEG, 80};
//
//     ret = OH_Image_Receiver_CreateImageReceiver(env, ohosImageReceiverInfo, &imageReceiver);
//
//     if (ret != IMAGE_RESULT_SUCCESS) {
//         OH_LOG_ERROR(LOG_APP, "OH_Image_Receiver_CreateImageReceiver failed. %{public}d", ret);
//         return nullptr;
//     }
//
//     if (imageReceiver == nullptr) {
//         OH_LOG_INFO(LOG_APP, "CreateImageReceiver is failed");
//         return nullptr;
//     }
//
//     if (imageReceiver == nullptr) {
//         OH_LOG_ERROR(LOG_APP, "imageReceiver is nullptr");
//         return result;
//     }

//    imageReceiverNative = OH_Image_Receiver_InitImageReceiverNative(env, imageReceiver);
    
    imageReceiverNative = OH_Image_Receiver_InitImageReceiverNative(env, args[1]);
    if (imageReceiverNative == nullptr) {
        OH_LOG_ERROR(LOG_APP, "ImageReceiverNative is nullptr");
        return result;
    }
    
    char surfaceId[128] = {0};
    ret = OH_Image_Receiver_GetReceivingSurfaceId (imageReceiverNative, surfaceId, sizeof(surfaceId));
    if (ret != IMAGE_RESULT_SUCCESS) {
        OH_LOG_ERROR(LOG_APP, "OH_Image_Receiver_GetReceivingSurfaceId is failed");
        return result;
    }
    
    if (InitCamera(surfaceId, xSurfaceId) == false) {
        OH_LOG_ERROR(LOG_APP, "InitCamera is failed");
        return result;
    }
    
    ret = OH_Image_Receiver_On(imageReceiverNative, []() {
        OH_LOG_ERROR(LOG_APP, "entry callBack");
        napi_value image;
        int32_t ret = OH_Image_Receiver_ReadLatestImage (imageReceiverNative, &image);
        if (ret != IMAGE_RESULT_SUCCESS ) {
            OH_LOG_ERROR(LOG_APP, "OH_Image_Receiver_ReadLatestImage is failed %{public}d", ret);
            return;
        }
        
        if (image == nullptr) {
            OH_LOG_ERROR(LOG_APP, "image is null");
            return ;
        }
        
        ImageNative *imageNative = OH_Image_InitImageNative(cur_env, image);
        if (imageNative == nullptr) {
            OH_LOG_ERROR(LOG_APP, "OH_Image_InitImageNative is failed");
            return;
        }
        
        struct OhosImageComponent imageInfo;
        ret = OH_Image_GetComponent(imageNative, 4, &imageInfo);
        if (ret != IMAGE_RESULT_SUCCESS) {
            OH_LOG_ERROR(LOG_APP, "OH_Image_GetComponent is failed");
            return;
        }
    });

    if (ret != IMAGE_RESULT_SUCCESS) {
        OH_LOG_ERROR(LOG_APP, "OH_Image_Receiver_On is failed");
        return result;
    }
    return result;
}


EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        {"InitImageReceiverNative", nullptr, InitImageReceiverNative, nullptr, nullptr, nullptr, napi_default, nullptr}
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}
